package SPA;

/**
 * Structured Pushdown Automaton
 */
public class SPA 
{
	private DFA[] automata = null;		// list of automatons
	
	public SPA()
	{
	}
	
	public SPA (DFA initialAutomaton)
	{
		this.automata = new DFA[1];		
		this.addAutomaton(initialAutomaton);
	}
	
	/**
	 * Gets an existing automaton of SPA
	 * @param automatonName		name of the automaton
	 * @return	the desired automaton, if it exists. else, returns null
	 */
	public DFA getAutomaton(String automatonName)
	{
		if (this.automata == null)
			return null;
		
		for (int i = 0; i < automata.length - 1; i++)
		{
			if (automata[i].getName().equals(automatonName.toLowerCase()))
			{
				return automata[i];
			}
		}
		return null;
	}
	
	/**
	 * Adds a automaton to the Stack
	 * @param state
	 */
	public void addAutomaton (DFA automaton)
	{
		if (this.automata == null)
		{
			this.automata = new DFA[1];		
		}
		
		if (this.verifyAutomaton(automaton))
		{
			automata[automata.length-1] = automaton;
			DFA [] temp = new DFA [automata.length + 1];
			System.arraycopy(automata, 0, temp, 0, automata.length);
			automata = temp;
		}
	}
	
	/**
	 * Verifies if the automaton already exists in the stack
	 * @param state		the automaton to be verified
	 * @return			TRUE if the automaton is Available (does not exist). Otherwise, FALSE (state already exists)
	 */
	private boolean verifyAutomaton (DFA automaton)
	{
		for (int i = 0; i < automata.length - 1; i++)
		{
			if (automaton.equals(automata[i]))
			{
				return false;
			}
		}
		return true;
	}
	
	public DFA[] getAutomata()
	{
		DFA[] temp = new DFA[this.automata.length-1];
		System.arraycopy(this.automata, 0, temp, 0, this.automata.length-1);
		return temp;
	}
	
	public String toString()
    {
        StringBuffer str = new StringBuffer();
        for (DFA automaton : getAutomata())
        {
        	str.append("Automaton: " + automaton);
        	str.append("\nInitial State: " + automaton.getInitialState());
        	for (DFAState state : automaton.getStates())
            {
        		str.append("\nState: " + state + (state.isFinal() ? " (FINAL)" : ""));
        		for (StateTransition transition : state.getStateTransitions())
        			str.append("\n\t" + transition);        		
                for (SubmachineCallTransition transition : state.getSubmachineCalls())
                	str.append("\n\t" + transition);
            }
        	str.append("\n\n");
        }        
        return str.toString();
    }
}
